from django.db import models
from django.contrib.auth.models import User
from datetime import datetime
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
import re

# Create your models here.
def default_serial():
    return int(datetime.strftime(datetime.now(), "%Y%m%d")+'00')

class SOA(models.Model):
    user    = models.ForeignKey(User)
    active  = models.BooleanField(default=True)
    origin  = models.CharField(max_length=255, unique=True)
    ttl     = models.PositiveSmallIntegerField("SOA TTL", default=86400, help_text=_("Number of seconds this zone may be cached before the source must be consulted again."))
    ns      = models.CharField(max_length=255, help_text=_("primary name server"))
    mbox    = models.CharField(max_length=255, help_text=_("Responsible person for this domain (email address with period instead of '@')"))
    serial  = models.IntegerField(default=default_serial(), help_text=_("zone serial number"))
    refresh = models.IntegerField(default=86400, help_text=_("How often secondaries should check if changes are made to the zone"))
    retry   = models.IntegerField(default=14400, help_text=_("How often secondaries attempt to fetch the zone if the first refresh fails"))
    expire  = models.IntegerField(default=2592000, help_text=_("How long the zone will be valid after a refresh.  Secondaries will discard the zone if no refresh could be made within this interval."))
    minimum = models.IntegerField("Min TTL", default=345600, help_text=_("Used as the default TTL for new records.  Also determines how long negative records are cached (such as record not found)"))
    
    def __str__(self):
        return "%s" % self.origin

    def records(self):
        return RR.objects.filter(zone=self)

    def get_absolute_url(self):
        return reverse('domain-detail', args=[self.id])

    class Meta:
        verbose_name = 'domain';

class RR(models.Model):
    TYPE_CHOICES = (
        ('A', 'A'),
        ('NS', 'NS'),
        ('MX', 'MX'),
        ('TXT', 'TXT'),
        ('CNAME', 'CNAME'),
        ('AAAA', 'AAAA'),
        ('SRV', 'SRV'),
        #('PTR', 'PTR'),
        #('ALIAS', 'ALIAS'),
        #('HINFO', 'HINFO'),
        #('NAPTR', 'NAPTR'),
        #('RP', 'RP'),
    )

    zone    = models.ForeignKey(SOA)
    name    = models.CharField(max_length=64)
    ttl     = models.IntegerField(default=86400)
    type    = models.CharField(max_length=5, choices=TYPE_CHOICES)
    aux     = models.IntegerField(max_length=3, default=0)
    data    = models.CharField(max_length=128)
    
    def __str__(self):
        return "%s %s %s %s" % (self.zone, self.name, self.type, self.data)

    def save(self, *args, **kwargs):
        super(RR, self).save(*args, **kwargs)
        soa = SOA.objects.get(pk=self.zone_id)
        soa.serial = soa.serial+1 if (default_serial() <= soa.serial) else default_serial()
        soa.save()

    def delete(self, *args, **kwargs):
        super(RR, self).delete(*args, **kwargs)
        soa = SOA.objects.get(pk=self.zone_id)
        soa.serial = soa.serial+1 if (default_serial() <= soa.serial) else default_serial()
        soa.save()

    def valid(self):
        if re.search(re.compile('\.$'), self.name):
            if not re.search(re.compile(self.zone.origin + '$'), self.name):
                return False
        if self.type == 'SRV':
            if re.match(re.compile('^\d{1,3}\s+(\d{1,4}|[1-5]\d{1,4}|6[0-4]\d{1,3}|65[0-4]\d{1,2}|655[0-2]\d|6553[0-5])\s+(\.|@|([a-z0-9][0-9a-z-]+(|\.))+)$'), self.data):
                if re.match(re.compile('^(\*|_[-_012349abBcCdefghijklLmnopqrsStTuvwWxyz]{2,17})\._(tcp|udp)(|\.+([a-z0-9][0-9a-z-]+(|\.))+)$'), self.name):
                    return True
        elif not re.match(re.compile('^(@|([a-z0-9][0-9a-z-]+(|\.))+)$'), self.name):
            return False
        elif self.type == "TXT":
            return True
        elif re.search(re.compile(' '), self.data):
            return False
        elif self.type == "CNAME":
            if RR.objects.filter(name=self.name).count() > 1:
                return False
            if self.name == '@':
                return False
            elif re.match(re.compile('^(@|([a-z0-9][0-9a-z-]+(|\.))+)$'), self.data):
                return True
        elif self.type == "MX":
            if re.match(re.compile('^(@|([a-z0-9][0-9a-z-]+(|\.))+)$'), self.data):
                return True
        elif self.type == "AAAA":
            import socket
            try:
                socket.inet_pton(socket.AF_INET6, self.data)
                return True
            except:
                return False
        elif self.type == "NS":
            if re.match(re.compile('^(@|([a-z0-9](|(|[0-9a-z-]+)[a-z0-9])\.)+)$'), self.data):
                return True
        elif self.type == "A":
            if not re.match(re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$'), self.data):
                return False
            else:
                return True
        return False

    class Meta:
        unique_together = (("zone", "name", "type", "data"),)
        ordering = ['name', 'type']

